/**************************************************************************//**
 * @file ezradio_hal.c
 * @brief This file contains EZRadio HAL.
 * @version 4.1.0
 ******************************************************************************
 * @section License
 * <b>(C) Copyright 2015 Silicon Labs, http://www.silabs.com</b>
 *******************************************************************************
 *
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 *
 * 1. The origin of this software must not be misrepresented; you must not
 *    claim that you wrote the original software.@n
 * 2. Altered source versions must be plainly marked as such, and must not be
 *    misrepresented as being the original software.@n
 * 3. This notice may not be removed or altered from any source distribution.
 *
 * DISCLAIMER OF WARRANTY/LIMITATION OF REMEDIES: Silicon Labs has no
 * obligation to support this Software. Silicon Labs is providing the
 * Software "AS IS", with no express or implied warranties of any kind,
 * including, but not limited to, any implied warranties of merchantability
 * or fitness for any particular purpose or warranties against infringement
 * of any proprietary rights of a third party.
 *
 * Silicon Labs will not be liable for any consequential, incidental, or
 * special damages, or any other relief, or for any claim by any third party,
 * arising from your use of this Software.
 *
 ******************************************************************************/

#include <stdlib.h>
#include <stdint.h>

#include "em_gpio.h"
#include "em_prs.h"

#include "spidrv.h"

#include "gpiointerrupt.h"
#include "ezradio_hal.h"

/// @cond DO_NOT_INCLUDE_WITH_DOXYGEN

static SPIDRV_HandleData_t  ezradioSpiHandle;
static SPIDRV_Handle_t      ezradioSpiHandlePtr = &ezradioSpiHandle;

#if (defined _EZR32_HAPPY_FAMILY)
static SPIDRV_Init_t        ezradioSpiInitData = SPIDRV_MASTER_USARTRF1;
#else
static SPIDRV_Init_t        ezradioSpiInitData = SPIDRV_MASTER_USARTRF0;
#endif

/// @endcond

/**
 * Configures the EZRadio GPIO port and pins
 *
 * @param[in] ezradioIrqCallback EZRadio interrupt callback configuration
 * @param[in] enablePTI If true enables the radio PTI bridge in the controller.
 */
void ezradio_hal_GpioInit( GPIOINT_IrqCallbackPtr_t ezradioIrqCallback, bool enablePTI )
{
#if (defined _EZR32_HAPPY_FAMILY)
  (void)enablePTI;
#endif

   GPIO_PinModeSet( (GPIO_Port_TypeDef) RF_USARTRF_CS_PORT, RF_USARTRF_CS_PIN, gpioModePushPull, 1 );

   /* Setup enable and interrupt pins to radio */
   GPIO_PinModeSet( (GPIO_Port_TypeDef) RF_SDN_PORT, RF_SDN_PIN, gpioModePushPull,  0 );
   GPIO_PinModeSet( (GPIO_Port_TypeDef) RF_INT_PORT, RF_INT_PIN, gpioModeInputPull, 1 );

   /* EZR32HG family uses hard wired PTI interface from the radio to the board controler */
#if !(defined _EZR32_HAPPY_FAMILY)
   if (enablePTI)
   {
     /* Setup PRS for PTI pins */
     CMU_ClockEnable(cmuClock_PRS, true);

     /* Configure RF_GPIO0 and RF_GPIO1 to inputs. */
     GPIO_PinModeSet((GPIO_Port_TypeDef)RF_GPIO0_PORT, RF_GPIO0_PIN, gpioModeInput, 0);
     GPIO_PinModeSet((GPIO_Port_TypeDef)RF_GPIO1_PORT, RF_GPIO1_PIN, gpioModeInput, 0);

     /* Pin PA0 and PA1 output the GPIO0 and GPIO1 via PRS to PTI */
     GPIO_PinModeSet(gpioPortA, 0, gpioModePushPull, 0);
     GPIO_PinModeSet(gpioPortA, 1, gpioModePushPull, 0);

     /* Disable INT for PRS channels */
     GPIO_IntConfig((GPIO_Port_TypeDef)RF_GPIO0_PORT, RF_GPIO0_PIN, false, false, false);
     GPIO_IntConfig((GPIO_Port_TypeDef)RF_GPIO1_PORT, RF_GPIO1_PIN, false, false, false);

     /* Setup PRS for RF GPIO pins  */
     PRS_SourceAsyncSignalSet(0, PRS_CH_CTRL_SOURCESEL_GPIOH, PRS_CH_CTRL_SIGSEL_GPIOPIN15);
     PRS_SourceAsyncSignalSet(1, PRS_CH_CTRL_SOURCESEL_GPIOH, PRS_CH_CTRL_SIGSEL_GPIOPIN14);
     PRS->ROUTE = (PRS_ROUTE_CH0PEN | PRS_ROUTE_CH1PEN);

     /* Make sure PRS sensing is enabled (should be by default) */
     GPIO_InputSenseSet(GPIO_INSENSE_PRS, GPIO_INSENSE_PRS);
   }
#endif //#if !(defined _EZR32_HAPPY_FAMILY)

   if (NULL != ezradioIrqCallback)
   {
       /* Register callback and enable interrupt */
       GPIOINT_CallbackRegister( RF_INT_PIN, ezradioIrqCallback );
       GPIO_IntConfig( (GPIO_Port_TypeDef) RF_INT_PORT, RF_INT_PIN, false, true, true );
   }

   return;
}

/**
 * Initializes SPI driver for the EZRadio device.
 */
void ezradio_hal_SpiInit( void )
{
   ezradioSpiInitData.bitRate   = 8E6;
   ezradioSpiInitData.csControl = spidrvCsControlApplication;

   SPIDRV_Init( ezradioSpiHandlePtr, &ezradioSpiInitData );

   return;
}

/**
 * Asserts SDN pin of the EZRadio device.
 */
void ezradio_hal_AssertShutdown(void)
{
  GPIO_PinOutSet( (GPIO_Port_TypeDef) RF_SDN_PORT, RF_SDN_PIN);
}

/**
 * Deasserts SDN pin of the EZRadio device.
 */
void ezradio_hal_DeassertShutdown(void)
{
  GPIO_PinOutClear( (GPIO_Port_TypeDef) RF_SDN_PORT, RF_SDN_PIN);
}

/**
 * Clears nSEL pin of the EZRadio device.
 */
void ezradio_hal_ClearNsel(void)
{
  GPIO_PinOutClear( (GPIO_Port_TypeDef) RF_USARTRF_CS_PORT, RF_USARTRF_CS_PIN);
}

/**
 * Sets nSEL pin of the EZRadio device.
 */
void ezradio_hal_SetNsel(void)
{
  GPIO_PinOutSet( (GPIO_Port_TypeDef) RF_USARTRF_CS_PORT, RF_USARTRF_CS_PIN);
}

/**
 * Reads nIRQ pin of the EZRadio device.
 *
 * @return Value of nIRQ pin.
 */
uint8_t ezradio_hal_NirqLevel(void)
{
  return GPIO_PinInGet( (GPIO_Port_TypeDef) RF_INT_PORT, RF_INT_PIN);
}

/**
 * Writes a single byte to the EZRadio SPI port.
 *
 * @param byteToWrite Byte to write.
 */
void ezradio_hal_SpiWriteByte(uint8_t byteToWrite)
{
  SPIDRV_MTransmitB(ezradioSpiHandlePtr, &byteToWrite, 1);
}

/**
 * Reads a single byte from the EZRadio SPI port.
 *
 * @param readByte Read byte.
 */
void ezradio_hal_SpiReadByte(uint8_t* readByte)
{
  SPIDRV_MReceiveB(ezradioSpiHandlePtr, readByte, 1);
}

/**
 * Writes byteCount number of bytes to the EZRadio SPI port.
 *
 * @param byteCount Number of bytes to write.
 * @param pData Pointer to the byte array.
 */
void ezradio_hal_SpiWriteData(uint8_t byteCount, uint8_t* pData)
{
  SPIDRV_MTransmitB(ezradioSpiHandlePtr, pData, byteCount);
}

/**
 * Reads byteCount number of bytes from the EZRadio SPI port.
 *
 * @param byteCount Number of bytes to write.
 * @param pData Pointer to the byte array.
 */
void ezradio_hal_SpiReadData(uint8_t byteCount, uint8_t* pData)
{

  SPIDRV_MReceiveB(ezradioSpiHandlePtr, pData, byteCount);
}
